#include "CNode.h"


CNode::CNode()
{
	singleNum = 0;
	yarnNum = 0;
}


CColorNode::CColorNode(char color, int colorNum)
{
	this->type = Color;
	this->color = color;
	this->singleNum = colorNum;
	this->yarnNum = colorNum;
}



CCycNode::CCycNode(int cycNum, int restNum)
{
	this->type = Cycle;

	this->cycNum = cycNum;
	this->restNum = restNum;
	this->childList = new CNode();
	this->currentChild = childList;
	this->currentChild->nextNode = childList;
}


CCycNode::~CCycNode()
{
	while(childList != childList->nextNode)
	{
		CNode * delNode = childList->nextNode;

		childList->nextNode = delNode->nextNode;
		delete delNode;
	}
	delete childList;
}


void CCycNode::CalcYarn()
{
	CNode * node = childList;
	int value = 0;

	do
	{
		value += node->yarnNum;
		if(node->type == Color)
		{
			CColorNode * colorNode = (CColorNode*)node;
		}

		node = node->nextNode;
	}
	while(node != childList);

	this->singleNum = value;
	this->yarnNum = value * this->cycNum + this->restNum;
}


void CCycNode::AddNode(CNode * newNode)
{
	/* Prepare */
	newNode->parentNode = this;
	newNode->nextNode = this->childList;
	/* Insert to tail */
	this->currentChild->nextNode = newNode;
	this->currentChild = newNode;

	if(newNode->type == Color)
	{
		CColorNode * node = (CColorNode*)newNode;
	}
	else if(newNode->type == Cycle)
	{
		CCycNode * node = (CCycNode*)newNode;
	}
}

/*

*/
CColorManager::CColorManager()
{
	rootCyc = new CCycNode(1, 0);
	crtCyc = rootCyc;
}

void CColorManager::AddColorNode(char color, int colorNum)
{
	CCycNode * crtCycNode = (CCycNode*)crtCyc;
	CColorNode * clrNode = new CColorNode(color, colorNum);

	crtCycNode->AddNode(clrNode);
}

void CColorManager::AddCycNode(int cycNum, int restNum)
{
	CCycNode * crtCycNode = (CCycNode*)crtCyc;
	CCycNode * cycNode = new CCycNode(cycNum, restNum);

	crtCycNode->AddNode(cycNode);

	crtCyc = cycNode;
}

void CColorManager::Init(char uiList[LIST_COUNT_MAX][STRING_LEN_MAX])
{
	int i = 0;

	while(uiList[i][0] != '\0')
	{
		char * item = uiList[i];
		CItemType itemType = GetType(item);

		switch(itemType)
		{
		case ColorDef:break;
		case SingleColor:
			{
				char color;
				int colorNum;

				GetColorItemInfo(item, color, colorNum);
				AddColorNode(color, colorNum);
			}
			break;
		case CycleStart:
			{
				int cycNum;
				int restNum;

				GetCycItemInfo(item, cycNum, restNum);
				AddCycNode(cycNum, restNum);
			}
			break;
		case CycleEnd:
			crtCyc->CalcYarn();
			crtCyc = crtCyc->parentNode;
			break;
		}
		i++;
	}
	crtCyc->CalcYarn();
}


CItemType CColorManager::GetType(char * item)
{
	char c = item[0];

	if(IS_CHAR(c))
	{
		return ColorDef;
	}
	else if(IS_NUM(c))
	{
		return SingleColor;
	}
	else if(IS_START(c))
	{
		return CycleStart;
	}
	else if(IS_END(c))
	{
		return CycleEnd;
	}
	return ILL_ITEM;
}


void CColorManager::GetColorItemInfo(char * item, char &color, int &colorNum)
{
	int numLen = 0;

	numLen = GetStringNum(item, colorNum);
	color = item[numLen];
}


void CColorManager::GetCycItemInfo(char * item, int &cycNum, int &restNum)
{
	int numLen = 0;

	numLen = GetStringNum(item + 2, cycNum);
	if(item[numLen + 2] == '+')
	{
		GetStringNum(item + 3 + numLen, restNum);
	}
	else
	{
		restNum = 0;
	}
}


int CColorManager::GetStringNum(char * item, int &num)
{
	int index = 0;
	int value = 0;

	while((item[index] >= '0') && (item[index] <= '9'))
	{
		value *= 10;
		value += item[index] - '0';
		index++;
	}
	num = value;

	return index;
}

CNode * CColorManager::SearchNode(CNode * node, int yarnNum)
{
	int value = 0;
	int lastValue = 0;

	CNode * head = node;
	node = node->nextNode;

	do
	{
		lastValue = value;
		value += node->yarnNum;
		if(yarnNum < value)
		{
			if(node->type == Color)
			{
				return node;
			}
			else if(node->type == Cycle)
			{
				CCycNode * cycNode = (CCycNode*)node;
				return SearchNode( cycNode->childList, (yarnNum - lastValue) % node->singleNum);
			}
		}
		else
		{
			node = node->nextNode;
		}
	}while(head != node);

	return head;
}


char CColorManager::GetColorByYarnNum(int yarnNum)
{
	CNode * node = this->rootCyc->childList;

	CColorNode * colorNode = (CColorNode *)SearchNode(node, yarnNum);

	return colorNode->color;

}


int CColorManager::GetYarnCount()
{
	return this->rootCyc->yarnNum;
}


static CColorManager * colorManager = NULL;

extern "C" void _declspec(dllexport) CreateColorManager()
{
	if(colorManager == NULL)
	{
		colorManager = new CColorManager();
	}
}

extern "C" void _declspec(dllexport) DeleteColorManager()
{
	if(colorManager != NULL)
	{
		delete colorManager;
		colorManager = NULL;
	}
}


extern "C" int _declspec(dllexport) InitColorManager(char uiList[LIST_COUNT_MAX][STRING_LEN_MAX])
{

#ifdef DEBUG
	FILE * fp;
	fopen_s(&fp, "uiList.bin", "wb+");
	fwrite(uiList, 100, 1, fp);
	fclose(fp);
#endif

	DeleteColorManager();
	CreateColorManager();

	colorManager->Init(uiList);
	return colorManager->GetYarnCount();
}

extern "C" int _declspec(dllexport) GetColorByYarnNum(int yarnNum)
{
	return (int)colorManager->GetColorByYarnNum(yarnNum);
}